package com.evildog.workspace.generator.gene;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
import com.baomidou.mybatisplus.generator.config.converts.PostgreSqlTypeConvert;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.evildog.workspace.common.object.PageQuery;
import com.evildog.workspace.common.result.PagedResult;
import com.evildog.workspace.common.result.Result;
import com.evildog.workspace.common.result.ResultGenerator;
import com.evildog.workspace.dependencies.mybatis.object.QueryConditionDTO;
import com.evildog.workspace.dependencies.mybatis.util.QueryConditionUtils;
import lombok.Data;
import org.springframework.cloud.openfeign.SpringQueryMap;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.util.Assert;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;

/**
 * TODO 以后有时间重构下代码生成，有点乱(￣.￣)
 */
@Data
public class BaseGenerator {

    protected AutoGenerator mpg;

    /**
     * 作者名
     */
    protected String author = "evildog";

    /**
     * 是否使用java8时间包
     */
    protected boolean isTimePack = true;

    /**
     * 代码所在服务名
     */
    protected String serviceName = "workspace-file";

    /**
     * 模块名
     */
    protected String moduleName = serviceName.split("-").length > 1 ? serviceName.split("-")[1] : serviceName;
    /**
     * 代码生成的包名
     */
    protected String packageName = "com.evildog.workspace";
    /**
     * 代码生成的地址
     */
    protected String packageDir = "D://workspace-code";

    /**
     * 需要去掉的表前缀
     */
    protected String[] tablePrefix = {"file_", "invest_", "sys_", "life_","t_","l_"};
    /**
     * 需要生成的表名(includeTables，excludeTables两者只能取其一)
     */
    protected String[] includeTables = {};

    /**
     * 需要排除的表名(includeTables，excludeTables两者只能取其一)
     */
    protected String[] excludeTables = {};
    /**
     * 逻辑删除字段
     */
    protected String logicDeleteFieldName = "is_deleted";
    /**
     * 是否包含基础业务字段
     */
    protected Boolean hasSuper = Boolean.FALSE;
    /**
     * 基础业务字段
     */
    protected String[] superEntityColumns = {"create_time", "create_user_id", "update_time", "update_user_id", "is_deleted"};

    /**
     * 不在dto / vo / bo 中的字段，即不传给前端的变量
     */
    protected String[] notInDTOColumns = {"update_user_id","create_user_id","is_deleted"};

    /**
     * 是否启用swagger
     */
    protected Boolean isSwagger2 = Boolean.TRUE;

    /**
     * entity 是否启用chainModel
     */
    protected Boolean chainModel = Boolean.TRUE;


    /**
     * 数据库驱动名
     */
    protected String driverName;

    /**
     * 数据库地址
     */
    protected String url;

    /**
     * 数据炬账号
     */
    protected String username;

    /**
     * 数据库密码
     */
    protected String password;

    /**
     * 自定义引入的三方类
     */
    protected Class<?>[] classes = new Class[]{
            Assert.class,
            List.class,
            PageQuery.class,
            PagedResult.class,
            QueryConditionDTO.class,
            QueryConditionUtils.class,
            ResultGenerator.class,
            Result.class,

            SpringQueryMap.class,
    };

    public void run(boolean last) {

        Properties props = getProperties();
        rewriteProperties(props);

        mpg = new AutoGenerator();
        // 全局配置
        mpg.setGlobalConfig(getGlobalConfig(last));
        // 数据库配置
        mpg.setDataSource(getDataSourceConfig(props));

        // 包配置
        mpg.setPackageInfo(getPackageConfig());

        // 自定义注入配置
        mpg.setCfg(getInjectionConfig());

        // 模板设置
        mpg.setTemplate(getTemplateConfig());

        // 设置模板引擎
        mpg.setTemplateEngine(new FreemarkerTemplateEngine());

        // 策略配置
        mpg.setStrategy(getStrategyConfig());


        mpg.execute();
    }

    protected InjectionConfig getInjectionConfig() {
        throw new RuntimeException("未指定生成模式");
    }

    /**
     * 通过properties重写属性
     */
    protected void rewriteProperties(Properties props) {


    }

    protected TemplateConfig getTemplateConfig() {
        return new TemplateConfig()
                .setEntity("templates/entityDO.java")
                .setController("templates/controller.java")
                .setService("templates/service.java")
                .setServiceImpl("templates/serviceImpl.java")
                .setMapper("templates/mapper.java")
                .setXml("templates/mapper.xml");
    }

    /**
     * 默认mvc模式
     */
    protected PackageConfig getPackageConfig() {
        PackageConfig pc = new PackageConfig();
        pc.setModuleName(moduleName);
        pc.setParent(packageName);
        pc.setController("controller");
        pc.setEntity("entity");
        pc.setXml("mapper.xml");
        pc.setMapper("mapper");
        pc.setService("service");
        pc.setServiceImpl("service.impl");
        return pc;
    }

    protected StrategyConfig getStrategyConfig() {
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        strategy.setTablePrefix(tablePrefix);

        //
        strategy.setTableFillList(Arrays.asList(
                new TableFill("create_user_id", FieldFill.INSERT),
                new TableFill("user_id", FieldFill.INSERT),
                new TableFill("create_time", FieldFill.INSERT),
                new TableFill("update_user_id", FieldFill.INSERT_UPDATE),
                new TableFill("update_time", FieldFill.INSERT_UPDATE))
        );

        strategy.setLogicDeleteFieldName(logicDeleteFieldName);
        if (includeTables.length > 0) {
            strategy.setInclude(includeTables);
        }
        if (excludeTables.length > 0) {
            strategy.setExclude(excludeTables);
        }

        if (hasSuper) {
//            strategy.setSuperEntityColumns(superEntityColumns);
//            strategy.setSuperServiceClass(BaseService.class);
//            strategy.setSuperServiceImplClass(BaseServiceImpl.class);
        }


        strategy.setChainModel(chainModel);
        strategy.setEntityLombokModel(true);
        strategy.setControllerMappingHyphenStyle(true);

        return strategy;
    }

    protected GlobalConfig getGlobalConfig(boolean last) {
        GlobalConfig gc = new GlobalConfig();
        String outputDir = getOutputDir();
        gc.setOutputDir(outputDir);
        gc.setAuthor(author);
        gc.setFileOverride(true);
        gc.setOpen(last);
        gc.setActiveRecord(false);
        gc.setEnableCache(false);
        gc.setBaseResultMap(true);
        gc.setBaseColumnList(true);
        gc.setMapperName("%sMapper");
        gc.setXmlName("%sMapper");
        gc.setServiceName("%sService");
        gc.setServiceImplName("%sServiceImpl");
        gc.setControllerName("%sController");
        if (isTimePack) {
            gc.setDateType(DateType.TIME_PACK);
        } else {
            gc.setDateType(DateType.ONLY_DATE);
        }
        gc.setSwagger2(isSwagger2);
        return gc;
    }

    protected DataSourceConfig getDataSourceConfig(Properties props) {
        DataSourceConfig dsc = new DataSourceConfig();

        String driverName = StrUtil.toString(props.getProperty("spring.datasource.driver-class-name"));
        if (driverName.contains(DbType.MYSQL.getDb())) {
            dsc.setDbType(DbType.MYSQL);
            dsc.setTypeConvert(new MySqlTypeConvert());
        } else if (driverName.contains(DbType.POSTGRE_SQL.getDb())) {
            dsc.setDbType(DbType.POSTGRE_SQL);
            dsc.setTypeConvert(new PostgreSqlTypeConvert());
        } else if (driverName.contains(DbType.ORACLE.getDb())) {
            dsc.setDbType(DbType.ORACLE);
            dsc.setTypeConvert(new PostgreSqlTypeConvert());
        } else {
            dsc.setDbType(DbType.MYSQL);
            dsc.setTypeConvert(new MySqlTypeConvert());
        }
        dsc.setDriverName(driverName);
        dsc.setUrl(StrUtil.isBlank(props.getProperty("spring.datasource.url")) ? this.url : props.getProperty("spring.datasource.url"));
        dsc.setUsername(StrUtil.isBlank(props.getProperty("spring.datasource.username")) ? this.username : props.getProperty("spring.datasource.username"));
        dsc.setPassword(StrUtil.isBlank(props.getProperty("spring.datasource.password")) ? this.password : props.getProperty("spring.datasource.password"));

        return dsc;
    }

    /**
     * 获取配置文件
     *
     * @return 配置Props
     */
    protected Properties getProperties() {
        // 读取配置文件
        Resource resource = new ClassPathResource("/application.properties");
        Properties props = new Properties();
        try {
            props = PropertiesLoaderUtils.loadProperties(resource);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return props;
    }

    /**
     * 生成到项目中
     *
     * @return outputDir
     */
    public String getOutputDir() {
        return (StrUtil.isBlank(packageDir) ? System.getProperty("user.dir") + "/" + serviceName : packageDir) + "/src/main/java";
    }

}
